﻿using System;

namespace BizElements.Core
{
    /// <summary>Provides immutable data used to create <see cref="DbRelation"/> objects.</summary>
    /// <typeparam name="TChild">Child metadata class.</typeparam>
    /// <typeparam name="TParent">Parent metadata class.</typeparam>
    [Serializable]
    public sealed class DbRelationConfiguration<TParent, TChild> : IDbRelationConfiguration
        where TParent : IDbTable, new()
        where TChild : IDbTable, new()
    {
        #region CTor.

        /// <summary>Initializes a new instance of <b>DbRelationConfiguration</b> class. Used for single-column keys.</summary>
        /// <param name="parentPrimaryKeyColumnName">Parent's primary key column name.</param>
        /// <param name="childForeignKeyColumnName">Child's foreign key column name.</param>
        public DbRelationConfiguration(string parentPrimaryKeyColumnName, string childForeignKeyColumnName)
        {
            this.ParentPrimaryKeyColumnNames = new string[] { parentPrimaryKeyColumnName };
            this.ChildForeignKeyColumnNames = new string[] { childForeignKeyColumnName };            
        }

        /// <summary>Initializes a new instance of <b>DbRelationConfiguration</b> class. Used for composite keys.</summary>
        /// <param name="parentPrimaryKeyColumnNames">Parent's foreign key column names.</param>
        /// <param name="childForeignKeyColumnNames">Child's foreign key column names.</param>        
        public DbRelationConfiguration(string[] parentPrimaryKeyColumnNames, string[] childForeignKeyColumnNames)
        {
            this.ParentPrimaryKeyColumnNames = parentPrimaryKeyColumnNames;
            this.ChildForeignKeyColumnNames = childForeignKeyColumnNames;            
        }

        /// <summary>Initializes a new instance of <b>DbRelationConfiguration</b> class. Used for composite keys.</summary>
        /// <param name="parentAlias">Optional parent alias.</param>
        /// <param name="childForeignKeyColumnNames">Child foreign key column names.</param>
        /// <param name="childAlias">Optional child alias.</param>
        /// <param name="parentPrimaryKeyColumnNames">Parent foreign key column names.</param>
        public DbRelationConfiguration(string parentAlias, string[] parentPrimaryKeyColumnNames, string childAlias, string[] childForeignKeyColumnNames)
        {
            this.ParentAlias = parentAlias;
            this.ParentPrimaryKeyColumnNames = parentPrimaryKeyColumnNames;
            this.ChildForeignKeyColumnNames = childForeignKeyColumnNames;
        }

        #endregion

        #region Parent.

        /// <summary>Get parent table/meta class.</summary>
        public Type ParentClass
        {
            get { return typeof(TParent); }
        }

        /// <summary>Gets names of parent primary key columns.</summary>
        public string[] ParentPrimaryKeyColumnNames { get; private set; }

        /// <summary>Gets optional parent table alias.</summary>
        public string ParentAlias { get; private set; }

        /// <summary>Creates an instance of parent table/meta class. Sets alias if <see cref="ParentAlias"/> property is not null.</summary>
        /// <returns>Parent metadata class.</returns>
        public IDbTable CreateParent()
        {
            TParent parent = new TParent();
            if (string.IsNullOrEmpty(this.ParentAlias))
                return parent;
            else
                return parent.Clone(this.ParentAlias);
        }

        #endregion

        #region Child properties and methods.

        /// <summary>Gets child table/meta class.</summary>
        public Type ChildClass
        {
            get { return typeof(TChild); }
        }

        /// <summary>Gets names of child foreign key columns.</summary>
        public string[] ChildForeignKeyColumnNames { get; private set; }

        /// <summary>Gets optional child table alias.</summary>
        public string ChildAlias { get; private set; }

        /// <summary>Creates an instance of child table/meta class. Sets alias if <see cref="ChildAlias"/> property is not null.</summary>
        /// <returns>Child metadata class.</returns>
        public IDbTable CreateChild()
        {
            TChild child = new TChild();
            if (string.IsNullOrEmpty(this.ChildAlias))
                return child;
            else
                return child.Clone(this.ChildAlias);
        }

        #endregion
    }
}
